package com.lr.frame.common.colorful.aop;

import java.util.ArrayList;
import java.util.List;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import javassist.NotFoundException;

import com.lr.frame.common.colorful.reflect.ClassTool;

public class AspectTool {

	private static class InitAspct {
		private static List<AspectHandler> aspectlist = new ArrayList<AspectHandler>();
		static {
			aspectlist.add(new StationAspect());
		}
	}

	public static List<AspectHandler> getAspectlist() {
		return InitAspct.aspectlist;
	}

	public static <E> E createProxyObj(Class<E> proxyTarget, Object proxyTargetObj) throws Exception {
		Class<?> proxyCalzz = AspectTool.createProxyClass(proxyTarget);
		return (E) proxyCalzz.getConstructor(proxyTarget).newInstance(proxyTargetObj);
	}

	public static <E> E createProxyObj(Class<E> proxyTarget) throws Exception {
		Class<?> proxyCalzz = AspectTool.createProxyClass(proxyTarget);
		return (E) proxyCalzz.getConstructor(proxyTarget).newInstance(proxyTarget.newInstance());
	}

	public static Class<?> createProxyClass(Class<?> proxyTarget) {
		try {
			CtClass proxyCalssCt = ClassTool.createProxyCt(proxyTarget);
			return addAspect(proxyCalssCt);
		} catch (NotFoundException e) {
			e.printStackTrace();
		} catch (CannotCompileException e) {
			e.printStackTrace();
		}
		return null;
	}

	private static Class<?>  addAspect(CtClass ctc) {
		try {

			ClassPool pool = ClassPool.getDefault();
			if (ctc.isFrozen()) {
				ctc.defrost();
			}
			CtField ctf = CtField.make(
					"public java.util.List aspectList=com.lr.os.commons.aop.AspectTool.getAspectlist();", ctc);
			ctc.addField(ctf);
			CtMethod[] ctms = ctc.getDeclaredMethods();
			String aopCodePrrfix="{if(this.aspectList!=null)for(int x=0;x<this.aspectList.size();x++){((com.lr.os.commons.aop.Aspect)this.aspectList.get(x))";
			for (CtMethod cthItem : ctms) {
				cthItem.addCatch(aopCodePrrfix+".throwing();}}",pool.get(Exception.class.getCanonicalName()));
				cthItem.insertBefore(aopCodePrrfix+".befor();}}");
				cthItem.insertAfter(aopCodePrrfix+".after();}}");
			}
			return ctc.toClass();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}
